package Gui.Dialogs;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Locale;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

import Cards.AuctionCard;
import Cards.DealCard;
import Gui.GameFrame;
import Main.Defines;
import PlayerManager.Player;

public class AuctionDialog extends JDialog {
	protected class CashLoanTracker {
		private int m_cash;
		private int m_loan;

		public CashLoanTracker() {
			m_cash = 0;
			m_loan = 0;
		}

		public CashLoanTracker(int cash, int loan) {
			m_cash = cash;
			m_loan = loan;
		}

		public void addCash(int cash) {
			m_cash += cash;
		}

		public void addLoan(int loan) {
			m_loan += loan;
		}

		public void setLoan(int loan) {
			m_loan = loan;
		}

		public void setCash(int cash) {
			m_cash = cash;
		}

		public int getCash() {
			return m_cash;
		}

		public int getLoan() {
			return m_loan;
		}
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 6609872132819558509L;
	private JPanel m_jp;
	private JPanel m_infoPanel;

	private JLabel m_currentBidLabel;
	private JLabel m_minimumBidLabel;
	private JLabel m_whichPlayerHasMaxBidLabel;
	private JLabel m_timeLeftLabel;

	private int m_minimumBid;
	private int m_currentBid;
	private int m_whichPlayerHasMaxBid;
	private long m_auctionTimer;
	private Timer m_gt;

	private ArrayList<CashLoanTracker> m_playerBidTracker;

	private final static long RESET_TIMER = 10;

	private AuctionCard m_prize;

	private static String removeChar(String s, char c) {
		String r = "";

		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) != c)
				r += s.charAt(i);
		}
		return r;
	}

	private DecimalFormat getDollarOnlyFormat() {
		DecimalFormatSymbols dollarsOnly = new DecimalFormatSymbols(Locale.US);

		String noCents = "$###,###";
		DecimalFormat noCentsFormat = new DecimalFormat(noCents, dollarsOnly);
		noCentsFormat.setGroupingSize(3);
		return noCentsFormat;
	}

	private void updateLabels() {
		m_currentBidLabel.setText(String
				.format("Current Bid: %s", getDollarOnlyFormat().format(m_currentBid)));
		m_minimumBidLabel.setText(String
				.format("Minimum Bid: %s", getDollarOnlyFormat().format(m_minimumBid)));
		m_whichPlayerHasMaxBidLabel.setText(String.format(
				"Player %d has bid lead", m_whichPlayerHasMaxBid + 1));
		// updateTimerLabel();
	}

	private ActionListener getMinBidActionListener(
			final JFormattedTextField text, final Player a) {
		return new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// make sure leading player is not allowed to bid
				if (m_whichPlayerHasMaxBid != a.getID()) {

					// if player has money for min bid
					if (a.getCash() >= m_minimumBid) {
						resetTracker();
						m_currentBid = m_minimumBid;
						m_minimumBid = m_currentBid + Defines.MINIMUM_BID_RESET;
						m_whichPlayerHasMaxBid = a.getID();
						// a.AddCash(-m_minimumBid);
						m_playerBidTracker.get(a.getID())
								.addCash(-m_minimumBid);
						if (!m_gt.isRunning())
							m_gt.start();
						m_auctionTimer = RESET_TIMER;

					}
					else {
						resetTracker();
						int moneyNeeded = m_minimumBid - a.getCash();
						int loanNeeded = moneyNeeded - moneyNeeded
								% Defines.LOAN_AMOUNT;
						// only add 1000 to needed if there was a remainder
						if (moneyNeeded % Defines.LOAN_AMOUNT != 0)
							loanNeeded += Defines.LOAN_AMOUNT;
						m_gt.stop();
						AskForLoanDialog showDialog = new AskForLoanDialog(a
								.getID(), moneyNeeded, " for bid.", loanNeeded);
						if (showDialog.isClosed() && showDialog.isLoanOK()) {
							// a.AddLoan(m_minimumBid - a.getCash());
							// a.setCash(0);
							m_playerBidTracker.get(a.getID()).setCash(
									moneyNeeded % Defines.LOAN_AMOUNT);
							m_playerBidTracker.get(a.getID()).addLoan(
									loanNeeded);
							if (!m_gt.isRunning())
								m_gt.start();
							m_auctionTimer = RESET_TIMER;
						}
						if (!m_gt.isRunning())
							m_gt.start();
					}

					updateLabels();
				}

			}
		};
	}

	private int getValueFromTextField(final JFormattedTextField text) {
		String formattedString = removeChar(text.getText(), '$');
		formattedString = removeChar(formattedString, ',');
		int val = Integer.parseInt(formattedString);
		text.setValue(val);
		text.setText(getDollarOnlyFormat().format(val));
		return val;
	}

	private ActionListener getBidButtonActionListener(
			final JFormattedTextField text, final Player a) {
		return new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					// make sure leading player is not allowed to bid
					if (m_whichPlayerHasMaxBid != a.getID()) {
						// gets string from textfield, gets its value,

						// check if value given by player meets the minimum
						// bid
						// requirement
						int val = getValueFromTextField(text);
						if (val < m_minimumBid) {
							text.setText("bid higher");
						}
						// player has enough money to bid his bid
						else if (val < a.getCash()) {
							m_currentBid = val;
							m_minimumBid = m_currentBid
									+ Defines.MINIMUM_BID_RESET;
							m_whichPlayerHasMaxBid = a.getID();
							// a.AddCash(-val);
							resetTracker();
							m_playerBidTracker.get(a.getID()).addCash(-val);
							if (!m_gt.isRunning())
								m_gt.start();
							m_auctionTimer = RESET_TIMER;
						}
						// player needs to take a loan to get bid
						else {
							int moneyNeeded = val - a.getCash();
							int loanNeeded = moneyNeeded - moneyNeeded
									% Defines.LOAN_AMOUNT;
							// only add 1000 to needed if there was a remainder
							if (moneyNeeded % Defines.LOAN_AMOUNT != 0)
								loanNeeded += Defines.LOAN_AMOUNT;
							m_gt.stop();
							AskForLoanDialog showDialog = new AskForLoanDialog(
									a.getID(), moneyNeeded, " for bid.",
									loanNeeded);
							if (showDialog.isClosed() && showDialog.isLoanOK()) {
								resetTracker();
								m_currentBid = val;
								m_minimumBid = val + Defines.MINIMUM_BID_RESET;
								m_whichPlayerHasMaxBid = a.getID();
								m_playerBidTracker.get(a.getID()).setCash(
										moneyNeeded % Defines.LOAN_AMOUNT);
								m_playerBidTracker.get(a.getID()).setLoan(
										loanNeeded);
								if (!m_gt.isRunning())
									m_gt.start();
								m_auctionTimer = RESET_TIMER;
							}
							if (!m_gt.isRunning())
								m_gt.start();
						}
					}
				}
				catch (NumberFormatException ex) {
					text.setText("Invalid Bid");
				}
				updateLabels();
				// TODO UNCOMMENT THIS WHEN COMPILED FOR THE GAME
				// GameFrame.getInstance().update();

			}
		};
	}

	private void buildUIContents() {
		NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);
		m_infoPanel = new JPanel();
		m_infoPanel.setLayout(new GridLayout(0, 1));

		m_currentBidLabel = new JLabel(String.format("Current Bid: %s",
				getDollarOnlyFormat().format(m_currentBid)));
		m_minimumBidLabel = new JLabel(String.format("Minimum Bid: %s",
				getDollarOnlyFormat().format(m_minimumBid)));
		m_timeLeftLabel = new JLabel(String.format("Time: %ds", m_auctionTimer));
		m_whichPlayerHasMaxBidLabel = new JLabel("");
		m_infoPanel.add(m_currentBidLabel);
		m_infoPanel.add(m_minimumBidLabel);
		m_infoPanel.add(m_whichPlayerHasMaxBidLabel);
		m_infoPanel.add(m_timeLeftLabel);
		m_whichPlayerHasMaxBid = -1; // initialized to an invalid player
		m_jp.add(m_infoPanel, BorderLayout.NORTH);
		JPanel playerPanel = new JPanel();
		playerPanel.setLayout(new GridLayout(0, 1));
		for (int i = 0; i < Defines.PLM.getPlayerList().size(); i++) {
			final Player a = Defines.PLM.getPlayerList().get(i);
			a.setID(i);
			JPanel row = new JPanel();
			final JFormattedTextField text = new JFormattedTextField(nf);
			text.setColumns(7);
			JButton bid = new JButton("Bid");
			bid.addActionListener(getBidButtonActionListener(text, a));
			JButton minimumBidButton = new JButton("Min Bid");
			minimumBidButton
					.addActionListener(getMinBidActionListener(text, a));
			row.add(text);
			row.add(bid);
			row.add(minimumBidButton);
			playerPanel.add(row);
		}
		m_jp.add(playerPanel, BorderLayout.CENTER);

	}

	private void resetTracker() {
		m_playerBidTracker = new ArrayList<CashLoanTracker>();
		for (Player a : Defines.PLM.getPlayerList())
			m_playerBidTracker
					.add(new CashLoanTracker(a.getCash(), a.getLoan()));

	}

	public AuctionDialog(final AuctionCard drawnCard) {
		//super(GameFrame.getInstance(), "Lottery Dialog", true);
		setModalityType(getModalityType().APPLICATION_MODAL);
		m_jp = new JPanel(new BorderLayout());
		m_jp.setLayout(Defines.getHeightStackedBorderLayout());
		m_jp.setBorder(Defines.getEmptyBorderConstraints());

		m_minimumBid = drawnCard.getCost();
		m_prize = drawnCard;
		m_auctionTimer = RESET_TIMER;
		m_gt = new Timer(Defines.TIMER_DELAY, new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				if (m_gt.isRunning()) {
					m_auctionTimer -= 1;
					m_timeLeftLabel.setText(String.format("Time: %ds",
							m_auctionTimer));
					if (m_auctionTimer <= 0) {
						for (int i = 0; i < m_playerBidTracker.size(); ++i) {
							Defines.PLM.getPlayerList().get(i).setCash(m_playerBidTracker.get(i).getCash());
							Defines.PLM.getPlayerList().get(i).setLoan(m_playerBidTracker.get(i).getLoan());

						}
						Defines.PLM.getPlayerList().get(m_whichPlayerHasMaxBid).addDealCard(drawnCard);
						m_gt.removeActionListener(this);
						@SuppressWarnings("unused")
						PlayerWinDialog showDialog = new PlayerWinDialog(AuctionDialog.this,
								m_whichPlayerHasMaxBid, m_prize);


					}
					repaint();
				}
			}
		});
		m_gt.setInitialDelay(Defines.TIMER_DELAY);

		// bidtracker tracks changes, winning player sets changes to cahs and
		// loan (other players don't get change in money)
		resetTracker();
		buildUIContents();
		add(m_jp);

		pack();
		if (getTitle() != null) {
			FontMetrics fm = getFontMetrics(getFont());
			int width = fm.stringWidth(getTitle()) + Defines.ICON_WIDTH;
			width = (int) Math.max(width * 1.2, getPreferredSize().getWidth());
			setSize(new Dimension(width, getHeight()));
		}
		setLocationRelativeTo(GameFrame.getInstance());
		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		setVisible(true);

	}

	protected class PlayerWinDialog extends JDialog {
		/**
		 * 
		 */
		private static final long serialVersionUID = 5568178599917488021L;
		private JPanel m_jp;

		public void buildUIContents(final JDialog parent, int playerWhoWon, AuctionCard prize) {
			JLabel showPlayerWinLabel = new JLabel(String.format(
					"Player %d WON the auction!!", playerWhoWon + 1));
			JLabel showPrize = new JLabel(String.format("You won a %s", prize
					.toString()));
			JButton ok = new JButton("OK");
			ok.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					dispose();
					parent.dispose();
				}
			});
			m_jp.add(showPlayerWinLabel, BorderLayout.NORTH);
			m_jp.add(showPrize, BorderLayout.CENTER);
			m_jp.add(ok);

		}

		public PlayerWinDialog(JDialog parent, int playerWhoWon,
				AuctionCard prize) {
			super(parent, String.format("Player %d WON the auction!!",
					playerWhoWon + 1), true);
			m_jp = new JPanel(new BorderLayout());
			m_jp.setLayout(Defines.getHeightStackedBorderLayout());
			m_jp.setBorder(Defines.getEmptyBorderConstraints());
			add(m_jp);
			buildUIContents(parent, playerWhoWon, prize);
			pack();
			if (getTitle() != null) {
				FontMetrics fm = getFontMetrics(getFont());
				int width = fm.stringWidth(getTitle()) + Defines.ICON_WIDTH;
				width = (int) Math.max(width * 1.2, getPreferredSize()
						.getWidth());
				setSize(new Dimension(width, getHeight()));
			}
			setLocationRelativeTo(GameFrame.getInstance());
			setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			setVisible(true);
		}
	}

	public static void main(String[] args) {
		ArrayList<Player> playerList = new ArrayList<Player>();
		Defines.PLM.initLotto();
		playerList.add(new Player());
		playerList.add(new Player());
		playerList.add(new Player());

		playerList.get(0).AddCash(2000);
		playerList.get(1).AddCash(8000);
		playerList.get(2).AddCash(0);

		@SuppressWarnings("unused")
		AuctionDialog showdDialog = new AuctionDialog(new AuctionCard(
				"Car", 8000, 1000));

	}
}
